// servicegroup
package serviceclient

import (
	"encoding/json"
	"io"
	"swim/etc"
	"swim/util/nuid"
	"time"
	//	"encoding/json"
	//	"fmt"
	"log"
	//"net/http"
	//	"strconv"
	"swim/redisclient"
	"sync"
)

type ServiceGroup struct {
	sync.RWMutex
	Clients    map[string]*ServiceClient
	MaxClients int
	Nuid       *nuid.NUID
}

func NewLoginGroup(max int) *ServiceGroup {
	group := new(ServiceGroup)
	group.Clients = make(map[string]*ServiceClient, max)
	group.MaxClients = max
	group.Nuid = nuid.New()
	return group
}

func (g *ServiceGroup) Broadcast(content string, fromLoginId string) {
	for _, client := range g.Clients {
		if client.LoginId == fromLoginId {
			continue
		} else {
			client.Write(content)
		}
	}
}

func (g *ServiceGroup) AddClient(user SUser, w io.Writer,
	RemoteAddr string) *ServiceClient {
	if len(g.Clients) > g.MaxClients {
		return nil
	}
	g.Lock()
	c := new(ServiceClient)
	c.Sessions = make(map[string]string)
	c.LoginId = g.Nuid.Next()
	c.User = user
	c.TaskPool = make(chan string, etc.S_MAX_MSG_POOL_SIZE)
	c.TaskFlag = etc.S_NO_SESSION
	c.LoginTime = time.Now()
	c.SesionTickCount = time.Now()
	c.CurGroup = g
	c.w = w
	c.Ip = RemoteAddr
	g.Clients[c.LoginId] = c
	g.Unlock()
	//本可登录的
	return c
}

//loginId为登录用户的会话ID
func (g *ServiceGroup) FindClientByLoginId(loginId string) (*ServiceClient, bool) {
	c := g.Clients[loginId]
	if c == nil {
		return nil, false
	}
	//c.On_Logout()
	return c, true

}

//根据服务人员账号查找登录的服务号
func (g *ServiceGroup) FindClientByAccount(account string) ([]*ServiceClient, bool) {
	var i = 0
	var sList []*ServiceClient
	for _, client := range g.Clients {
		if client.User.Account == account {
			sList[i] = client
			return sList, true
		}
	}
	return nil, false
}

func (g *ServiceGroup) FindClientByGroupAccount(groupAccount string) (map[string]*ServiceClient, bool) {
	var bRet = false
	var groupUser = make(map[string]*ServiceClient)
	g.RLock()
	defer g.RUnlock()
	for loginId, client := range g.Clients {
		if client.User.Group.Account == groupAccount {
			groupUser[loginId] = client
			bRet = true
		}
	}
	return groupUser, bRet
}

func (g *ServiceGroup) RemoveClient(loginId string) bool {
	c := g.Clients[loginId]
	if c == nil {
		return false
	}
	c.On_Logout()
	g.Lock()
	delete(g.Clients, loginId)
	g.Unlock()
	return true
}

//查找在线客服人员
func (g *ServiceGroup) FindOnlineService(groupAccount string) (*ServiceClient, bool) {
	//从redis找，或从集群服务器上找
	var svrClient *ServiceClient = &ServiceClient{}
	var minSession = 0
	var bFind = false
	gMap, ok := g.FindClientByGroupAccount(groupAccount)
	if ok {
		svrClient.SesionTickCount = time.Now()
		for _, client := range gMap {
			nClientTask := len(client.Sessions)
			if nClientTask == 0 {
				svrClient = client
				bFind = true
				break
			} else {
				if minSession == 0 {
					minSession = nClientTask
				}
				if nClientTask < minSession {
					svrClient.SesionTickCount = client.SesionTickCount
					minSession = nClientTask
					svrClient = client
					bFind = true
				} else {
					if client.SesionTickCount.Before(svrClient.SesionTickCount) {
						svrClient.SesionTickCount = client.SesionTickCount
						svrClient = client
						bFind = true
					}
				}
			}

		}
		return svrClient, bFind
	}
	return nil, false
}

//清除过期过期用户
func (g *ServiceGroup) StartGC() {
	go g.vaccuum()
}

//check timeout
func (g *ServiceGroup) vaccuum() {

	for {
		<-time.After(etc.S_GC_SESSION_TIME * time.Second)
		if g.Clients == nil {
			return
		}
		for sid := range g.Clients {
			g.itemExpired(sid)
		}
	}

	return
}
func (g *ServiceGroup) itemExpired(sid string) bool {
	g.Lock()
	defer g.Unlock()

	itm, ok := g.Clients[sid]
	if !ok {
		return true
	}
	if itm.isExpire() {
		delete(g.Clients, sid)
		return true
	}
	return false
}

func (g *ServiceGroup) StartPushOnlineUsers() {
	go g.pushOnlineUsers()
}
func (g *ServiceGroup) pushOnlineUsers() {
	for {
		<-time.After(etc.S_REFRESH_USER_TIME * time.Second)
		g.pushAllUser()
	}
	return
}
func (g *ServiceGroup) pushAllUser() {
	if g.Clients == nil {
		return
	}
	users := []SUser{}
	g.Lock()
	for _, c := range g.Clients {
		users = append(users, c.User)
	}
	g.Unlock()
	userBytes, err := json.Marshal(users)
	if err == nil {
		_, sErr := redisclient.G_redisPool.Get().Do("SETEX", etc.OnlineServiceUsers,
			etc.S_REFRESH_USER_TIME, string(userBytes))
		if sErr != nil {
			log.Println(sErr)
		}
	}
}

func (g *ServiceGroup) pushUser(itm *ServiceClient) bool {
	itm.rdLock.RLock()
	defer itm.rdLock.RUnlock()

	user, err := json.Marshal(itm.User)
	if err == nil {
		_, rErr := redisclient.G_redisPool.Get().Do("HSET", etc.OnlineServiceUsers,
			itm.User.Account, user)
		redisclient.G_redisPool.Get().Do("EXPIRE", etc.OnlineServiceUsers, etc.S_REFRESH_USER_TIME)
		if rErr != nil {
			return false
		}
	} else {
		return false
	}
	return true
}
